#include "GCamera.h"
GCamera::GCamera(Vector3f eye, Vector3f target, Vector3f up, float fAspect) : m_vEye(eye), m_vTarget(target), m_vUp(up), m_fAspect(fAspect)
{
	UpdateCameraAxis();
	m_persp = GenProjectionMatrix(m_fFov, m_fAspect, m_fNear, m_fFar);
}

void GCamera::UpdateMatrix()
{
	UpdateCameraAxis();
	GenViewMatrix();
	m_vp = m_persp * m_view;
}

void GCamera::UpdateCameraAxis()
{
	z = (m_vEye - m_vTarget).normalized();
	x = (m_vUp.cross(z)).normalized();
	y = (z.cross(x)).normalized();
}

Matrix4f GCamera::GenProjectionMatrix(float fFov, float fAspect, float fNear, float fFar)
{
	float fHalfFov = fFov / 2;
	float fHalfRad = fHalfFov / 180.0f * PI;
	
	float fHalfH = std::tan(fHalfRad) * fNear * -1;
	float fHalfW = fHalfH * fAspect;

	// CubicDefineBy [l,r] [b,t] [n,f]
	float fl = -fHalfW;
	float fr = fHalfW;
	float fb = -fHalfH;
	float ft = fHalfH;
	float fn = fNear;
	float ff = fFar;

	Eigen::Matrix4f ortho;
	ortho << 2 / (fr - fl), 0, 0, 0,
		0, 2 / (ft - fb), 0, 0,
		0, 0, 2 / (fn - ff), 0,
		0, 0, 0, 1;
	
	Eigen::Matrix4f ortho_move;
	ortho_move << 1, 0, 0, -0.5f * (fr + fl),
		0, 1, 0, -0.5f * (ft + fb),
		0, 0, 1, -0.5f * (fn + ff),
		0, 0, 0, 1;

	ortho = ortho * ortho_move;

	Eigen::Matrix4f persp_ortho;
	persp_ortho << fn, 0, 0, 0,
		0, fn, 0, 0,
		0, 0, fn + ff, -fn* ff,
		0, 0, 1, 0;

	return ortho * persp_ortho;
}

Matrix4f GCamera::GenViewMatrix()
{
	Matrix4f matIdentify = Matrix4f::Identity();
	m_view << x.x(), x.y(), x.z(), 0,
		y.x(), y.y(), y.z(), 0,
		z.x(), z.y(), z.z(), 0,
		0, 0, 0, 1;

	m_view(0, 3) = -m_vEye.x();
	m_view(1, 3) = -m_vEye.y();
	m_view(2, 3) = -m_vEye.z();
	
	return m_view;
}